#include "ConnSession.h"
#include "ServiceEx.h"
#include "IoSocketEx.h"
using namespace std;
using namespace SGLib;

CConnSession::CConnSession(u64 sid, const char *ip, s32 port, SGLib::IPacketParser *parser) :
    m_sid(sid),
    m_ip(ip),
    m_port(port),
    m_baseSession(NULL),
    m_parser(parser),
    m_state(E_ConnSession_Break),
    m_stateLock()
{
}

CConnSession::~CConnSession()
{
}

void CConnSession::OnConnected(SGLib::CIoSocketEx *session)
{
    m_baseSession = session;
    _SetState( E_ConnSession_Connected );
    
    _DoSendMsgCache();
}

void CConnSession::OnClose()
{
    m_baseSession = NULL;
    _SetState( E_ConnSession_Break );
    LOG_WARN( "[%s][%s][%d]", __FILE__, __FUNCTION__, __LINE__ );
}

void CConnSession::SendMsg(u32 msgid, const IMessage &msg)
{
    static byte buf[CIoSocketEx::E_MaxPkg_Len];
    s32 headlen = m_parser->GetHeadLen();
    s32 msglen = msg.SerializeToArray( (char*)buf+headlen, CIoSocketEx::E_MaxPkg_Len-headlen );
    if( msglen == IMessage::E_Error )
    {
        LOG_ERROR( "[%s][%s][%d] to[%llu] msgid[%u] SerializeToArray failed", 
            __FILE__, __FUNCTION__, __LINE__,
            m_sid, msgid );
        return;
    }

    s32 pkglen = msglen + headlen;
    m_parser->FillHeader( buf, pkglen, msgid );
    SendMsg( buf, pkglen );
}

void CConnSession::SendMsg(const byte *data, s32 len)
{
    s8 state = _GetState();
    if( state == E_ConnSession_Connected )
    {
        SELF_ASSERT(m_baseSession, return;);
        if( !m_baseSession->Send(data, len) )
        {
            LOG_ERROR( "[%s][%s][%d] to[%llu] Send Failed", __FILE__, __FUNCTION__, __LINE__, m_sid );
        }
    }
    else
    {
        string msg( (const char*)data, len );
        m_msgs.push_back( msg );
        if( state == E_ConnSession_Break )
        {
            Connect();
        }
    }
}
	
void CConnSession::SendMsgWithHead(u32 msgid, const IMessage &msg, char *head, int len)
{
    static byte buf[CIoSocketEx::E_MaxPkg_Len];
    s32 headlen = m_parser->GetHeadLen();
	s32 msglen = msg.SerializeToArray( (char*)buf+headlen+len, sizeof(buf)-headlen-len );
    if( msglen == IMessage::E_Error )
    {
        LOG_ERROR( "[%s][%s][%d] to[%llu] msgid[%u] SerializeToArray failed", 
            __FILE__, __FUNCTION__, __LINE__,
            m_sid, msgid );
        return;
    }

	memcpy( buf+headlen, head, len );
	s32 totallen = msglen + headlen + len;
	m_parser->FillHeader( (byte*)buf, totallen, msgid );
    SendMsg( buf, totallen );
}

void CConnSession::Connect()
{
    s8 state = _GetState();
    LOG_WARN( "[%s][%s][%d] m_state[%d]", 
        __FILE__, __FUNCTION__, __LINE__, state );
    if( state != E_ConnSession_Break )
    {
        return;
    }
    if( m_sid != 0 && m_ip != "" && m_port != 0 )
    {
        _SetState( E_ConnSession_Connecting );
        _Connect();
    }
}

void CConnSession::_Connect()
{
    IServiceEx *service = CServiceExManager::Instance().GetServiceEx();
    SELF_ASSERT( service, return; );
    UserData ud;
    ud.u64d = m_sid;
    service->Connect( m_ip.c_str(), m_port, &ud );
    LOG_INFO( "[%s][%s][%d] connect[%llu][%s:%d]", __FILE__, __FUNCTION__, __LINE__,
        m_sid, m_ip.c_str(), m_port );
}

void CConnSession::_DoSendMsgCache()
{
    SELF_ASSERT(m_baseSession, return;);
    LOG_INFO( "[%s][%s][%d] try send[%d] msg to[%llu]", __FILE__, __FUNCTION__, __LINE__, 
        m_msgs.size(), m_sid );
    std::deque<std::string>::iterator it = m_msgs.begin();
    for( ; it != m_msgs.end(); ++it )
    {
        if( !m_baseSession->Send((const byte*)it->c_str(), it->length()) )
        {
            LOG_ERROR( "[%s][%s][%d] Send to[%llu] Failed", __FILE__, __FUNCTION__, __LINE__, m_sid );
        }
    }
    m_msgs.clear();
}

void CConnSession::_SetState(s8 state)
{
    CGuardLock<CLock> g(m_stateLock);
    m_state = state;
}

s8 CConnSession::_GetState()
{
    s8 state;
    {
        CGuardLock<CLock> g(m_stateLock);
        state = m_state;
    }
    return state;
}

